home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C ++ / Frameworks / MacZoop 1.6.5 / More Classes / Window Classes / ZDragDropWindow.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-03-17  |  15.6 KB  |  647 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            ObjectMacZapp        -- a standard Mac OOP application template
  5. *
  6. *
  7. *
  8. *            ZDragDropWindow.cpp   -- the window object with drag and drop
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *            © 1996, Graham Cox
  15. *
  16. *
  17. *
  18. *
  19. *************************************************************************************************/
  20.  
  21. #include    "ZDragDropWindow.h"
  22. #include    "MacZoop.h"
  23.  
  24. static pascal OSErr    ZWTrackingHandler(DragTrackingMessage theMsg, WindowPtr theWindow, void* refCon,
  25.                                         DragReference theDrag);
  26. static pascal OSErr    ZWDropHandler(WindowPtr theWindow, void* refCon, DragReference theDrag);
  27.  
  28.  
  29.  
  30. static DragTrackingHandlerUPP    gDragTrackProc = NewDragTrackingHandlerProc(ZWTrackingHandler);
  31. static DragReceiveHandlerUPP    gDragReceiveProc = NewDragReceiveHandlerProc(ZWDropHandler);
  32.  
  33.  
  34.  
  35.  
  36. /*--------------------------------***  CONSTRUCTOR  ***---------------------------------*/
  37. /*    
  38.  
  39. create this window object. This has no special initialisation
  40.  
  41. ----------------------------------------------------------------------------------------*/
  42.  
  43. ZDragDropWindow::ZDragDropWindow(ZCommander* aBoss,  const short windowID)
  44.     : ZWindow(aBoss, windowID)
  45. {
  46. }
  47.  
  48. /*--------------------------------***  DESTRUCTOR  ***----------------------------------*/
  49. /*    
  50.  
  51. remove the handlers, if installed
  52.  
  53. ----------------------------------------------------------------------------------------*/
  54.  
  55. ZDragDropWindow::~ZDragDropWindow()
  56. {
  57.     if (MacHasDM())
  58.         RemoveDragHandlers();
  59. }
  60.  
  61.  
  62.  
  63. /*--------------------------------***  INITZWINDOW  ***---------------------------------*/
  64. /*    
  65.  
  66. overridable initialiser. This does the normal initialisation, then installs the handlers
  67.  
  68. ----------------------------------------------------------------------------------------*/
  69.  
  70. void    ZDragDropWindow::InitZWindow()
  71. {
  72.     inherited::InitZWindow();
  73.     
  74.     if (MacHasDM())
  75.         InstallDragHandlers();
  76. }
  77.  
  78.  
  79.  
  80. /*------------------------------------***  DRAG  ***------------------------------------*/
  81. /*    
  82.  
  83. initiate a drag from this window
  84.  
  85. ----------------------------------------------------------------------------------------*/
  86.  
  87. void    ZDragDropWindow::Drag( const Point startPt )
  88. {
  89.     // this can be called to instigate a drag from this window. When your mouse dragging method
  90.     // wants to perform a drag, it calls this. This then builds the drag region and drag data
  91.     // by calling some additional methods. You can override those methods to implement the drag
  92.     // data, etc you require. <startPt> is in local coordinates, as passed from Click, e.g.
  93.     
  94.     DragReference     theDrag;
  95.     RgnHandle        dragRgn = NULL;
  96.     unsigned short    diCount;
  97.     EventRecord        theEvent;
  98.     
  99.     if (MacHasDM())
  100.     {
  101.         // make absolutely sure we are the current port, etc.
  102.         
  103.         Focus();
  104.         FailOSErr(NewDrag(&theDrag));
  105.         
  106.         // add data to the drag
  107.         
  108.         try
  109.         {
  110.             MakeDragData(theDrag);    
  111.     
  112.             // if no data was added to the drag (the default case, in fact) do not
  113.             // bother to do anything else
  114.             
  115.             FailOSErr(CountDragItems(theDrag, &diCount));
  116.             
  117.             if (diCount > 0)
  118.             {
  119.                 // make a drag region
  120.                 
  121.                 FailNIL(dragRgn = MakeDragRgn());
  122.                 
  123.                 // make a dummy event record
  124.                 
  125.                 theEvent.what = mouseDown;
  126.                 theEvent.where = startPt;
  127.                 LocalToGlobal(&theEvent.where);
  128.                 theEvent.when = TickCount();
  129.                 theEvent.message = 0;
  130.                 theEvent.modifiers = 0;
  131.                 
  132.                 // do that drag manager thang!
  133.                 
  134.                 FailOSErr(TrackDrag(theDrag, &theEvent, dragRgn));
  135.             }
  136.         }
  137.         catch (OSErr err)
  138.         {
  139.             // do not propagate exceptions
  140.         }
  141.         
  142.         DisposeDrag(theDrag);
  143.         
  144.         if (dragRgn)
  145.             DisposeRgn(dragRgn);
  146.     }
  147. }
  148.  
  149.  
  150.  
  151. /*--------------------------------***  MAKEDRAGDATA  ***--------------------------------*/
  152. /*    
  153.  
  154. add data to the drag (as much as you want)
  155.  
  156. ----------------------------------------------------------------------------------------*/
  157.  
  158. void        ZDragDropWindow::MakeDragData( const DragReference theDrag )
  159. {
  160.     // override to add your data to the drag. You will do this normally by using drag manager
  161.     // calls such as AddDragItemFlavor .
  162.  
  163.     
  164. }
  165.  
  166.  
  167.  
  168.  
  169. /*--------------------------------***  MAKEDRAGRGN  ***---------------------------------*/
  170. /*    
  171.  
  172. create the drag outline. This uses the content rect by default
  173.  
  174. ----------------------------------------------------------------------------------------*/
  175.  
  176. RgnHandle    ZDragDropWindow::MakeDragRgn()
  177. {
  178.     // override to build the drag region you require. By default, the drag region is the content
  179.     // region of the window.
  180.     
  181.     Rect        content;
  182.     RgnHandle    dragRgn, temp;
  183.     Point        origin = {0,0};
  184.  
  185.     FailNIL(dragRgn = NewRgn());
  186.     FailNIL(temp = NewRgn());
  187.     
  188.     GetContentRect(&content);
  189.     RectRgn(dragRgn, &content);
  190.     CopyRgn(dragRgn, temp);
  191.     InsetRgn(temp, 1, 1);
  192.     DiffRgn(dragRgn, temp, dragRgn);
  193.     
  194.     DisposeRgn(temp);
  195.     
  196.     // convert into global corrdinates
  197.     
  198.     LocalToGlobal(&origin);
  199.     OffsetRgn(dragRgn, origin.h, origin.v);
  200.     
  201.     return dragRgn;
  202. }
  203.  
  204.  
  205. /*------------------------------------***  DROP  ***------------------------------------*/
  206. /*    
  207.  
  208. Handle the drop from an item in a drag onto this window
  209.  
  210. ----------------------------------------------------------------------------------------*/
  211.  
  212. void    ZDragDropWindow::Drop( const OSType flavour, const Ptr data, const long dataSize)
  213. {
  214.     // called for each item in a drag for which AcceptsFlavour returns TRUE. The data is already
  215.     // extracted into Ptr and the size of it is given in dataSize. The flavour type allows you
  216.     // to cast the ptr to any expected structure. The default method does nothing- override to
  217.     // implement your own behaviour.
  218.  
  219. }
  220.  
  221.  
  222. /*---------------------------------***  DRAGHILITE  ***---------------------------------*/
  223. /*    
  224.  
  225. hilite the window in response to a drag over it
  226.  
  227. ----------------------------------------------------------------------------------------*/
  228.  
  229. void    ZDragDropWindow::DragHilite( const Boolean state, const DragReference theDrag)
  230. {
  231.     // hilites the window. This uses the drag manager's default hiliting.
  232.     
  233.     RgnHandle    dragHiliteRgn;
  234.     Rect        content;
  235.     
  236.     Focus();
  237.     
  238.     if (state)
  239.     {
  240.         // make the hilite region
  241.         
  242.         FailNIL(dragHiliteRgn = NewRgn());    
  243.     
  244.         GetContentRect(&content);
  245.         RectRgn(dragHiliteRgn, &content);
  246.         
  247.         (void) ShowDragHilite(theDrag, dragHiliteRgn, TRUE);
  248.         
  249.         DisposeRgn(dragHiliteRgn);
  250.     }
  251.     else
  252.         (void) HideDragHilite(theDrag);
  253.  
  254. }
  255.  
  256.  
  257. /*----------------------------***  INSTALLDRAGHANDLERS  ***-----------------------------*/
  258. /*    
  259.  
  260. install the procs that call this during a drag
  261.  
  262. ----------------------------------------------------------------------------------------*/
  263.  
  264. void    ZDragDropWindow::InstallDragHandlers()
  265. {
  266.     // set up the drag handler proc to call this object when a drag occurs over this window. The
  267.     // window's refCon field contains the object reference, so the handler can find this object.
  268.     
  269.     FailOSErr(InstallTrackingHandler(gDragTrackProc,     macWindow, 0L));
  270.     FailOSErr(InstallReceiveHandler (gDragReceiveProc,     macWindow, 0L));    
  271. }
  272.  
  273.  
  274. /*----------------------------***  REMOVEDRAGHANDLERS  ***------------------------------*/
  275. /*    
  276.  
  277. get rid of the handlers. This is called by the destructor
  278.  
  279. ----------------------------------------------------------------------------------------*/
  280.  
  281. void    ZDragDropWindow::RemoveDragHandlers()
  282. {
  283.     // removes the drag handlers when the window is deleted
  284.     
  285.     OSErr    theErr;
  286.     
  287.     theErr = RemoveTrackingHandler(gDragTrackProc,     macWindow);    
  288.     theErr = RemoveReceiveHandler (gDragReceiveProc,macWindow);    
  289. }
  290.  
  291.  
  292.  
  293. /*------------------------------***  ACCEPTSFLAVOUR  ***--------------------------------*/
  294. /*    
  295.  
  296. return TRUE if this given flavour can be dropped here
  297.  
  298. ----------------------------------------------------------------------------------------*/
  299.  
  300. Boolean    ZDragDropWindow::AcceptsFlavour( const OSType aFlavour)
  301. {
  302.     // called with each flavour a drag contains. Return TRUE for each one that can be
  303.     // handled. By default, this simply returns TRUE, indicating that all flavours are
  304.     // accepted. Override to get the behaviour you want.
  305.  
  306.     return TRUE;
  307. }
  308.  
  309.  
  310.  
  311. /*--------------------------------***  DROPHANDLER  ***---------------------------------*/
  312. /*    
  313.  
  314. unpacks the data from an accepted drag and passes it to the Drop method.
  315.  
  316. ----------------------------------------------------------------------------------------*/
  317.  
  318. void    ZDragDropWindow::DropHandler( const DragReference theDrag )
  319. {
  320.     // method to dispatch drops from the drag manager. This unpacks the drag data, and for
  321.     // each flavour that the AcceptsFlavour method returns TRUE for, will call Drop with the
  322.     // data of the item.
  323.     
  324.     unsigned short    dragItemCount, i;
  325.     unsigned short    dragFlavourCount, f;
  326.     ItemReference    iRef;
  327.     FlavorType        theFlavour;
  328.     Boolean            atLeastOneAccepted = FALSE;
  329.     Size            dataSize;
  330.     Ptr                theData = NULL;
  331.     
  332.     curDragRef = theDrag;
  333.     
  334.     DragHilite(FALSE, theDrag);
  335.     FailOSErr(CountDragItems(theDrag, &dragItemCount));
  336.     
  337.     SetBeachBallCursor();
  338.     
  339.     for (i = 1; i <= dragItemCount; i++)
  340.     {
  341.         // get the item
  342.         
  343.         FailOSErr(GetDragItemReferenceNumber(theDrag, i, &iRef));    
  344.     
  345.         // count the flavours in the item
  346.         
  347.         FailOSErr(CountDragItemFlavors(theDrag, iRef, &dragFlavourCount));
  348.         
  349.         // for each flavour, if we can accept the flavour, unpack it and pass the data
  350.         // to the drop method.
  351.         
  352.         for (f = 1; f <= dragFlavourCount; f++)
  353.         {
  354.             FailOSErr(GetFlavorType(theDrag, iRef, f, &theFlavour));
  355.         
  356.             if (AcceptsFlavour(theFlavour))
  357.             {
  358.                 // get the data for this object
  359.                 
  360.                 FailOSErr(GetFlavorDataSize(theDrag, iRef, theFlavour, &dataSize));
  361.                 
  362.                 // create a buffer big enough to hold the object
  363.                 
  364.                 FailNIL(theData = NewPtr(dataSize));
  365.                 
  366.                 // get the data into the buffer
  367.                 
  368.                 try
  369.                 {
  370.                     FailOSErr(GetFlavorData(theDrag, iRef, theFlavour, theData, &dataSize, 0L));
  371.                 
  372.                     // call the method to handle the drop
  373.                     
  374.                     Drop(theFlavour, theData, dataSize);    
  375.                 }
  376.                 catch(OSErr err)
  377.                 {
  378.                     if (theData)
  379.                         DisposePtr(theData);
  380.                         
  381.                     theData = NULL;
  382.                     
  383.                     throw err;    
  384.                 }    
  385.                 if (theData)
  386.                     DisposePtr(theData);
  387.                     
  388.                 theData = NULL;
  389.                 atLeastOneAccepted = TRUE;
  390.             }
  391.         }
  392.     }
  393.     
  394.     // if nothing in this drag was accepted (unlikely???), throw an error
  395.     // so that the drag manager gives the right feedback
  396.     
  397.     if (! atLeastOneAccepted)
  398.         FailOSErr(paramErr);
  399.         
  400.     curDragRef = NULL;
  401. }
  402.  
  403.  
  404.  
  405. /*-------------------------------***  TRACKTHEDRAG  ***---------------------------------*/
  406. /*    
  407.  
  408. dispatches tracking messages to the appropriate method
  409.  
  410. ----------------------------------------------------------------------------------------*/
  411.  
  412.  
  413. void    ZDragDropWindow::TrackTheDrag( const DragTrackingMessage theMessage, const DragReference theDrag)
  414. {
  415.     // this method handles the tracking of a drag within this window. It calls various other
  416.     // methods to implement its behaviour- normally you would override those where necessary
  417.     // rather than this, which is quite low-level.
  418.     
  419.     curDragRef = theDrag;
  420.     
  421.     switch (theMessage)
  422.     {    
  423.         case dragTrackingEnterHandler:
  424.             EnteredHandler(theDrag);
  425.             break;
  426.         case dragTrackingEnterWindow:
  427.             EnteredWindow(theDrag);
  428.             break;
  429.         case dragTrackingInWindow:
  430.             InWindow(theDrag);
  431.             break;
  432.         case dragTrackingLeaveWindow:
  433.             LeftWindow(theDrag);
  434.             break;
  435.         case dragTrackingLeaveHandler:
  436.             LeftHandler(theDrag);
  437.             break;
  438.     }
  439.     
  440.     curDragRef = NULL;
  441. }
  442.  
  443. /*------------------------------***  ENTEREDHANDLER  ***--------------------------------*/
  444. /*    
  445.  
  446. the handler was entered
  447.  
  448. ----------------------------------------------------------------------------------------*/
  449.  
  450. void    ZDragDropWindow::EnteredHandler( const DragReference theDrag)
  451. {
  452.     // default method does nothing
  453. }
  454.  
  455.  
  456. /*-------------------------------***  ENTEREDWINDOW  ***--------------------------------*/
  457. /*    
  458.  
  459. the window was made the target of the drag. This hilites it if any flavour in the drag is
  460. acceptable.
  461.  
  462. ----------------------------------------------------------------------------------------*/
  463.  
  464. void    ZDragDropWindow::EnteredWindow( const DragReference theDrag)
  465. {
  466.     // the drag has enetered this window. If the window accepts any of the flavours in the drag,
  467.     // hilite the window.
  468.  
  469.     unsigned short    dragItemCount;
  470.     unsigned short    dragFlavourCount;
  471.     ItemReference    iRef;
  472.     FlavorType        theFlavour;
  473.     
  474.     
  475.     
  476.     FailOSErr(CountDragItems(theDrag, &dragItemCount));
  477.     
  478.     if (dragItemCount)
  479.     {
  480.         do
  481.         {
  482.             // for each drag item, count the flavours
  483.             
  484.             FailOSErr(GetDragItemReferenceNumber(theDrag, dragItemCount, &iRef));
  485.             FailOSErr(CountDragItemFlavors(theDrag, iRef, &dragFlavourCount));
  486.             
  487.             // for each flavour, see if we can accept it. As soon as we get one that we can
  488.             // handle, we hilite the window and exit.
  489.             
  490.             do
  491.             {
  492.                 FailOSErr(GetFlavorType(theDrag, iRef, dragFlavourCount, &theFlavour));    
  493.             
  494.                 if (AcceptsFlavour(theFlavour))
  495.                 {
  496.                     DragHilite(TRUE, theDrag);
  497.                     return;
  498.                 }
  499.             }
  500.             while(--dragFlavourCount);
  501.         }
  502.         while(--dragItemCount);
  503.     }
  504. }
  505.  
  506.  
  507. /*----------------------------------***  INWINDOW  ***----------------------------------*/
  508. /*    
  509.  
  510. called repeatedly while the drag is over this window
  511.  
  512. ----------------------------------------------------------------------------------------*/
  513.  
  514. void    ZDragDropWindow::InWindow( const DragReference theDrag)
  515. {
  516.     // called repeatedly as long as the drag is within the window. Override to do other things,
  517.     // such as hilite items within the window, etc.
  518. }
  519.  
  520.  
  521. /*---------------------------------***  LEFTWINDOW  ***---------------------------------*/
  522. /*    
  523.  
  524. the drag is no longer in this window. This unhilites the drag here.
  525.  
  526. ----------------------------------------------------------------------------------------*/
  527.  
  528. void    ZDragDropWindow::LeftWindow( const DragReference theDrag)
  529. {
  530.     // Ladies and Gentlemen, the drag has left the window. Please leave in an orderly fashion.
  531.     
  532.     DragHilite(FALSE, theDrag);
  533. }
  534.  
  535.  
  536. /*--------------------------------***  LEFTHANDLER  ***---------------------------------*/
  537. /*    
  538.  
  539. the drag has left this handler
  540.  
  541. ----------------------------------------------------------------------------------------*/
  542.  
  543.  
  544. void    ZDragDropWindow::LeftHandler( const DragReference theDrag)
  545. {
  546.     // default method does nothing
  547. }
  548.  
  549.  
  550.  
  551.  
  552. /*----------------------------------***  MACHASDM  ***----------------------------------*/
  553. /*    
  554.  
  555. static function returns TRUE if Drag Manager is present. Checks link on PowerMacs.
  556.  
  557. ----------------------------------------------------------------------------------------*/
  558.  
  559. Boolean        MacHasDM()
  560. {
  561.     // returns TRUE if drag manager is installed on this mac and is loaded by the CFM.
  562.     
  563.     long    gResult;
  564.     OSErr    theErr;
  565.     Boolean    hasDM = FALSE;
  566.     
  567.     theErr = Gestalt(gestaltDragMgrAttr, &gResult);
  568.     
  569.     if ((theErr == noErr) &&
  570.         (gResult & 1))
  571.     {
  572.         #if GENERATINGCFM 
  573.             // check that the dragLib is loaded and linked
  574.             
  575.             hasDM = (NewDrag != (void*) kUnresolvedCFragSymbolAddress);
  576.     
  577.         #else
  578.             hasDM = TRUE;
  579.         #endif
  580.     }
  581.     return hasDM;
  582. }
  583.  
  584.  
  585.  
  586. /*--------------------------------*********************---------------------------------*/
  587. /*    
  588.  
  589. static functions follow. Do not modify them directly- all features can be acessed by
  590. overriding the appropriate methods.
  591.  
  592. ----------------------------------------------------------------------------------------*/
  593.  
  594. static pascal OSErr    ZWTrackingHandler(DragTrackingMessage theMsg, WindowPtr theWindow, void* refCon,
  595.                                     DragReference theDrag)
  596. {
  597.     ZDragDropWindow*    zdWindow = NULL;
  598.     OSErr                theErr = noErr;
  599.     
  600.     // get the object
  601.     
  602.     if (theWindow)
  603.         zdWindow = (ZDragDropWindow*) (GetZWindow(theWindow));
  604.  
  605.     try
  606.     {
  607.         FailNIL(zdWindow);
  608.         
  609.         zdWindow->TrackTheDrag(theMsg, theDrag);
  610.     }
  611.     catch(OSErr err)
  612.     {
  613.         theErr = err;
  614.     }
  615.     
  616.     return theErr;
  617. }
  618.  
  619.  
  620. /*--------------------------------*********************---------------------------------*/
  621.  
  622. static pascal OSErr    ZWDropHandler(WindowPtr theWindow, void* refCon, DragReference theDrag)
  623. {
  624.     ZDragDropWindow*    zdWindow = NULL;
  625.     OSErr                theErr = noErr;
  626.     // get the object
  627.     
  628.     if (theWindow)
  629.         zdWindow = (ZDragDropWindow*) (GetZWindow(theWindow));
  630.  
  631.     try
  632.     {
  633.         FailNIL(zdWindow);
  634.         
  635.         zdWindow->DropHandler(theDrag);
  636.     }
  637.     catch(OSErr err)
  638.     {
  639.         SysBeep(1);
  640.         theErr = err;
  641.     }
  642.     
  643.     return theErr;
  644. }
  645.  
  646. /*--------------------------------*********************---------------------------------*/
  647.